package config

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"gitee.com/xiawucha365/sago.v2/core/util"
	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
)

// 程序配置
type Config struct {
	v *viper.Viper
	AppName    string `json:"app_name"`
	AppVersion string `json:"app_version"`
	Conf       string
	Debug      bool
	RunEnv     string
	Beans      string
	Mysql      MysqlConfig
	Redis      RedisConfig
	Mongodb      MongodbConfig
	Log        LogConfig
}


func NewConfig(opt *FlagOption) *Config {
	cf := new(Config)
	//读取配置文件
	_ = loadConfigFromToml(cf, opt)



	//命令行参数优先
	cf.RunEnv = opt.RunEnv
	cf.Conf = opt.Conf
	if opt.Debug {
		cf.Debug = opt.Debug
	}

	if opt.Beans != "all" {
		cf.Beans = opt.Beans
	}

	//日志配置处理
	if cf.Log.LogDir == "" {
		cf.Log.LogDir = util.GetExecutePath()
	}

	//监听配置文件改动
	go func() {
		if err  := WatchConfig(cf,opt); err != nil {
			panic(err)
		}
	}()
	return cf
}

func loadConfigFromToml(cf *Config, opt *FlagOption) *Config {
	v := viper.New()
	v.SetConfigType("toml")
	v.SetConfigFile(opt.Conf)
	err := v.ReadInConfig()
	if err != nil {
		log.Fatal("read config failed: %v", err)
	}

	bs, err := json.Marshal(v.AllSettings())
	if err != nil {
		log.Fatalf("unable to marshal config to toml: %v", err)
	} else {
		if err := util.JsonDecode(bs, cf); err != nil {
			panic(err)
		}
	}

	cf.v = v
	return cf
}

//监听配置文件的修改和变动
func WatchConfig(cf *Config, opt *FlagOption) error {
	//if err := loadConfigFromToml(cf,opt); err !=nil{
	//	panic(err)
	//}
	ctx, cancel := context.WithCancel(context.Background())

	cf.v.WatchConfig()

	//监听回调函数
	watch := func(e fsnotify.Event) {
		log.Printf("配置文件已被修改: %s \n", e.String())
		fmt.Println("before:")
		util.PrintType(cf)
		//重载
		loadConfigFromToml(cf,opt)
		fmt.Println("after:")
		util.PrintType(cf)
		cancel()
	}

	cf.v.OnConfigChange(watch)
	<-ctx.Done()
	return nil
}



type MysqlConfig struct {
	Addr     string
	Username string
	Password string
	Charset  string
	Dbname   string
	Engine   string
}

type RedisConfig struct {
	Addr     string
	Password string
}

type MongodbConfig struct {
	Addrs     []string
	Username string
	Password string
	Dbname   string
	ReplicaSet	string `json:"replica_set"`
	Engine   string
}

type LogConfig struct {
	LogDir        string `json:"log_dir,omitempty"` //日志存放目录
	//MaxSize       int8   //日志文件最大
	//MaxBackups    int8   //最多备份数量
	Level        string   //日志级别，只保留某级别以上日志 info error warning
	MaxAge        int16  `json:"max_age"` //最多保留天数
	SplitDuration string   `json:"split_duration"` //切割周期-天/月
}

